/**
 * A class that represents a dispatchCenter that holds an emercyBoard with emergencies, a garage with units and 
 * dispatchers & operators working in the center!
 *
 * 
 * @author Vincent Goelen, Jelle Stroobants, Simon Versteele, Niels Sterckx
 */

package dispatch;

import hospital.Hospital;

import java.util.*;

import unit.Garage;
import unit.Unit;

import movement.Location;

import emergency.*;

/**
 * Class for creating a DispatchCenter
 */
public class DispatchCenter {

	/**
	 * Variable containing the name of this DispatchCenter
	 */
	private String name;

	/**
	 * Variable containing the location of this DispatchCenter
	 */
	private final Location location;

	/**
	 * Variable containing a board which contains all emergencies
	 */
	private EmergencyBoard emergencyboard;

	/**
	 * Variable containing the garage in which all units are placed
	 */
	private Garage garage;

	/**
	 * Variable in which all the dispatchers working in the center are stored
	 */
	private ArrayList<Dispatcher> dispatchers;

	/**
	 * Variable in which all the operators working in the center are stored
	 */
	private ArrayList<Operator> operators;

	/**
	 * Variable in which the current date and time are stored
	 */
	private Clock clock;

	/**
	 * Method for creating a dispatchCenter with given name, location and
	 * location of garage
	 * 
	 * @param name
	 *            The name of this dispatchcenter
	 * 
	 * @param location
	 *            The location for this dispatchcenter
	 * 
	 * @param garageLocation
	 *            The location of the garage of this dispatch center
	 * 
	 * @post The name of this dispatch center is set to the given name
	 * 
	 * @post An empty list with dispatchers is created
	 * 
	 * @post An empty list with operators is created
	 * 
	 * @post A garage is created for this dispatch center, with the given
	 *       garageLocation
	 * 
	 * @post An empty list with emergencies is created
	 * 
	 * @post The clock in this dispatch center is initialized with 0 hours and 0
	 *       minutes
	 * 
	 * @throws IllegalArgumentException
	 *             , if the location of this dispatch center is invalid
	 */
	public DispatchCenter(String name, Location location,
			Location garageLocation) {
		setName(name);
		setDispatchers(new ArrayList<Dispatcher>());
		setOperators(new ArrayList<Operator>());
		setGarage(new Garage(garageLocation, this));
		setEmergencyboard(new EmergencyBoard(this));

		if (canHaveAsLocation(location))
			this.location = location;
		else
			throw new IllegalArgumentException(
					"A DispatchCenter can't be created without a valid location");
		this.clock = new Clock(0, 0);
	}

	/**
	 * Adds the given dispatcher to the list of operators
	 * 
	 * @param dispatcher
	 *            the dispatcher that's going to be added to this DispatchCenter
	 * 
	 * @throws IllegalArgumentException
	 *             if the dispatcher is not a valid dispatcher
	 */
	public void addDispatcher(Dispatcher dispatcher) {
		if (isValidDispatcher(dispatcher))
			dispatchers.add(dispatcher);
		else
			throw new IllegalArgumentException(
					"This dispatcher can't be added to the dispatchers of this dispatchcenter");
	}

	/**
	 * Method for adding an emergency to this dispatch center it's emergency
	 * board
	 * 
	 * @param e
	 *            The emergency you want to add to the emergency list
	 * 
	 * @post The given emergency is added to this dispatch center it's emergency
	 *       list
	 * 
	 * @throws IllegalArgumentException
	 *             ,if the emergency can't be added
	 */
	public void addEmergencyToDispatchCenter(Emergency e) {
		try {
			getEmergencyboard().addEmergency(e);
		} catch (Exception ex) {
			throw new IllegalArgumentException(
					"The given emergency can't be added to the emergencyboard ");
		}
	}

	/**
	 * Adds the given operator to the list of operators
	 * 
	 * @param operator
	 *            the operator that's going to be added to this DispatchCenter
	 * 
	 * @throws IllegalArgumentException
	 *             if the operator is not a valid operator
	 */
	public void addOperator(Operator operator) throws IllegalArgumentException {
		if (isValidoperator(operator))
			operators.add(operator);
		else
			throw new IllegalArgumentException(
					"This operator can't be added to the operators of this dispatchcenter");
	}

	/**
	 * Method for checking a Location can be assigned to this Garage
	 * 
	 * @param Location
	 *            The location you want to check for validity
	 * 
	 * @return Returns true if valid (not null), false if not
	 */
	private boolean canHaveAsLocation(Location location) {
		return (location != null);
	}

	/**
	 * Method for getting the available units for this DispatchCenter
	 * 
	 * @return Returns a list with units available for dispatch
	 */
	public ArrayList<Unit> getAvailableUnits() {
		return getGarage().getAvailableUnits();
	}

	/**
	 * Method for getting the available units of the given type for this
	 * DispatchCenter
	 * 
	 * @return Returns a list with units (from the given type) available for
	 *         dispatch
	 */
	public ArrayList<Unit> getAvailableUnits(String type) {
		return getGarage().getAvailableUnits(type);
	}

	/**
	 * A method to get the clock
	 * 
	 * @return Returns the clock
	 */
	public Clock getClock() {
		return this.clock;
	}

	/**
	 * Returns the dispatcher with the given name
	 * 
	 * @param name
	 *            The name of the dispatcher that is being searched for
	 * 
	 * @return The dispatcher with the given name
	 * 
	 * @throws IllegalArgumentException
	 *             , if the given name is not a dispatcher name
	 */
	public Dispatcher getDispatcher(String name) {
		Dispatcher dispatcher = null;
		for (Dispatcher o : dispatchers) {
			if (isValidDispatcher(o) && o.getName().equals(name))
				dispatcher = o;
		}
		if (dispatcher == null) {
			throw new IllegalArgumentException("This dispatcher doesn't exist");
		}
		return dispatcher;
	}

	/**
	 * Returns the dispatchers working in the current DispatchCenter
	 * 
	 * @return Returns the dispatchers working in the current DispatchCenter
	 */
	@SuppressWarnings("unused")
	private ArrayList<Dispatcher> getDispatchers() {
		return dispatchers;
	}

	/**
	 * Returns the (a cloned list) dispatchers working in the current
	 * DispatchCenter
	 * 
	 * @return Returns the dispatchers working in the current DispatchCenter
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<Dispatcher> getDispatchersClone() {
		return (ArrayList<Dispatcher>) dispatchers.clone();
	}

	/**
	 * Returns a list of emergencies of which the type is the same as the given
	 * type as param
	 * 
	 * @param type
	 *            The type that all emergencies in the list must be off
	 * 
	 * @return Returns a list of emergencies from the given type
	 */
	public ArrayList<Emergency> getEmergenciesFromType(String type) {
		return getEmergencyboard().getEmergenciesFromType(type);
	}

	/**
	 * Returns the emergencyBoard on which all the emergencies of this
	 * DispatchCenter are written
	 * 
	 * @return Returns the emergencyBoard on which all the emergencies of this
	 *         DispatchCenter are written
	 */
	public EmergencyBoard getEmergencyboard() {
		return emergencyboard;
	}

	/**
	 * Returns the garage in which the units of the current DispatchCenter are
	 * located
	 * 
	 * @return Returns the garage in which the units of the current
	 *         DispatchCenter are located
	 */
	public Garage getGarage() {
		return garage;
	}

	/**
	 * A method to get a list of all hospitals
	 * 
	 * @return Returns a list of hospitals that are closest to the given
	 *         location
	 */
	public ArrayList<Hospital> getHospitals() {
		return getGarage().getHospitals();
	}

	/**
	 * A method to get a list of hospitals that are closest to the given
	 * location
	 * 
	 * @param location
	 *            The location to look up the nearest hospitals to this location
	 * 
	 * @return Returns a list of hospitals (ordered by distance to given
	 *         location)
	 */
	public ArrayList<Hospital> getHospitals(Location location) {
		return getGarage().getHospitals(location);
	}

	/**
	 * Returns the location of the current DispatchCenter
	 * 
	 * @return Returns the location of this DispatchCenter
	 */
	public Location getLocation() {
		return location;
	}

	/**
	 * Returns the name of the current DispatchCenter
	 * 
	 * @return Returns the name of the current DispatchCenter
	 */
	public String getName() {
		return this.name;
	}

	/**
	 * Returns the operator with the given name
	 * 
	 * @param naam
	 *            The name of the operator that is being searched for
	 * 
	 * @return Returns the operator with the given name, if he exists
	 * 
	 * @throws IllegalArgumentException
	 *             , if the given name is not an operator name
	 */
	public Operator getOperator(String name) {
		Operator operator = null;
		for (Operator o : operators) {
			if (isValidoperator(o) && o.getName().equals(name))
				operator = o;
		}
		if (operator == null) {
			throw new IllegalArgumentException("This operator doesn't exist");
		}
		return operator;
	}

	/**
	 * Returns the operators working in the current DispatchCenter
	 * 
	 * @return Returns a list with the operators working in the current
	 *         DispatchCenter
	 */
	@SuppressWarnings("unused")
	private ArrayList<Operator> getOperators() {
		return operators;
	}

	/**
	 * Returns the (cloned list with) operators working in the current
	 * DispatchCenter
	 * 
	 * @return Returns a (cloned) list with the operators working in the current
	 *         DispatchCenter
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<Operator> getOperatorsClone() {
		return (ArrayList<Operator>) operators.clone();
	}

	/**
	 * Returns if the given operator is a valid dispatcher
	 * 
	 * @param o
	 *            The dispatcher that needs to be checked if it is valid or not
	 * 
	 * @return Returns true if the given dispatcher is valid False if the given
	 *         dispatcher is invalid
	 */
	private boolean isValidDispatcher(Dispatcher o) {
		if (o.getName() == "InValid")
			return false;
		return true;
	}

	/**
	 * Returns if the given operator is a valid operator
	 * 
	 * @param o
	 *            The operator that needs to be checked if it is valid or not
	 * 
	 * @return Returns true if the given operator is valid False if the given
	 *         operator is invalid
	 */
	private boolean isValidoperator(Operator o) {
		if (o.getName() == "InValid")
			return false;
		return true;
	}

	/**
	 * Method for setting the dispatchers of this DispatchCenter
	 * 
	 * @param dispatchers
	 *            The dispatchers of this DispatchCenter
	 * 
	 * @post the dispatchers of this DispatchCenter is changed into the given
	 *       dispatchers
	 * 
	 * @throws IllegalArgumentException
	 *             if the list with dispatchers is null
	 */
	private void setDispatchers(ArrayList<Dispatcher> dispatchers) {
		if (dispatchers != null)
			this.dispatchers = dispatchers;
		else
			throw new IllegalArgumentException(
					"The list of dispatcher of an dispatchcenter may not be null");
	}

	/**
	 * Method for setting the emergencyBoard of this DispatchCenter
	 * 
	 * @param emergencyboard
	 *            The new emergencyBoard of this DispatchCenter
	 * 
	 * @post The emergencyBoard of this DispatchCenter is changed into the given
	 *       emergencyBoard
	 * 
	 * @throws IllegalArgumentException
	 *             if the given emergencyBoard is null
	 */
	private void setEmergencyboard(EmergencyBoard emergencyboard) {
		if (emergencyboard != null)
			this.emergencyboard = emergencyboard;
		else
			throw new IllegalArgumentException(
					"The emergencyboard of an dispatchcenter may not be null");
	}

	/**
	 * Method for setting the garage of this DispatchCenter
	 * 
	 * @param garage
	 *            The garage of this DispatchCenter
	 * 
	 * @post The garage of this DispatchCenter is changed into the given garage
	 * 
	 * @throws IllegalArgumentException
	 *             if the given garage is null, or if the location of the given
	 *             garage is null
	 */
	private void setGarage(Garage garage) {
		if (garage == null)
			throw new IllegalArgumentException(
					"The garage of an dispatchcenter may not be null");
		else if (!canHaveAsLocation(garage.getLocation()))
			throw new IllegalArgumentException(
					"The location of the garage of an dispatchcenter may not be null");
		else
			this.garage = garage;
	}

	/**
	 * Method for setting the name of this DispatchCenter
	 * 
	 * @param name
	 *            The name of this DispatchCenter
	 * 
	 * @post The name of this DispatchCenter is changed into the given name
	 * 
	 * @throws IllegalArgumentException
	 *             if the given name is null
	 */
	private void setName(String name) {
		if (name != null)
			this.name = name;
		else
			throw new IllegalArgumentException(
					"The name of an dispatchcenter may not be null");
	}

	/**
	 * Method for setting the operators of this DispatchCenter
	 * 
	 * @param operators
	 *            The operators of this DispatchCenter
	 * 
	 * @post the operators of this DispatchCenter is changed into the given
	 *       operators
	 * 
	 * @throws IllegalArgumentException
	 *             if the list with operators is null
	 */
	private void setOperators(ArrayList<Operator> operators) {
		if (operators != null)
			this.operators = operators;
		else
			throw new IllegalArgumentException(
					"The list of operators of an dispatchcenter may not be null");
	}

}
